use std::num::NonZeroU32;
use super::Result;
use data_encoding::HEXUPPER;
use ring::{digest, pbkdf2};


pub fn pbkdf2_secret(password: String, salt: String) -> Result<String> {
    const CREDENTIAL_LEN: usize = digest::SHA256_OUTPUT_LEN;
    let n_iter = NonZeroU32::new(100_000).unwrap();

    let salt = salt.as_bytes();

    let mut pbkdf2_hash = [0u8; CREDENTIAL_LEN];
    pbkdf2::derive(
        pbkdf2::PBKDF2_HMAC_SHA256,
        n_iter,
        salt,
        password.as_bytes(),
        &mut pbkdf2_hash,
    );
    Ok(HEXUPPER.encode(&pbkdf2_hash))
}


pub fn pbkdf2_secret_verify(password: String, password_hash: String, salt: String) -> Result<()> {
    let n_iter = NonZeroU32::new(100_000).unwrap();

    let salt = salt.as_bytes();

    let result = pbkdf2::verify(
        pbkdf2::PBKDF2_HMAC_SHA256,
        n_iter,
        salt,
        password.as_bytes(),
        &HEXUPPER.decode(password_hash.as_ref()).unwrap(),
    )?;
    Ok(result)
}

#[cfg(test)]
mod tests {
    use crate::secret::{pbkdf2_secret, pbkdf2_secret_verify};

    #[test]
    fn test_pbkdf2_secret() {
        let _password = pbkdf2_secret("password".to_string(), "1234567890".to_string()).unwrap();
        println!("{}", _password);
        match pbkdf2_secret_verify("password".to_string(), _password, "1234567890".to_string()) {
            Ok(_) => {
                println!("pbkdf2_secret_verify ok!")
            }
            Err(err) => { println!("pbkdf2_secret_verify err:{}", err) }
        }
    }
}